using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input.Touch;

namespace The_LarX
{
    public class InputManager
    {
        public GamePadState GamePadState;
        public GamePadState LastGamePadState;

        public readonly KeyboardState[] CurrentKeyboardStates;
        public readonly GamePadState[] CurrentGamePadStates;

        public readonly KeyboardState[] LastKeyboardStates;
        public readonly GamePadState[] LastGamePadStates;

        public MouseState LastMouseState;
        public MouseState MouseState;

        public const int MaxInputs = 4;

        public TouchCollection Touches;
        public List<GestureSample> Gestures;

        public Dictionary<Enum, Buttons> ButtonsAssignments;
        public Dictionary<Enum, Keys> KeysAssignments;

        /// <summary>
        /// The Playing Player GamePad Index
        /// </summary>
        public PlayerIndex PlayingPlayer = PlayerIndex.One;

        /// <summary>
        /// If, when one of the players press the START button, 
        /// the Engine should show a message and change the PlayingPlayer Index
        /// to the Player that pressed the START button.
        /// Very useful for single player games, you can change the main gamepad
        /// by only pressing the StartButton.
        /// </summary>
        public bool PlayingPlayerStartChange = true;

        public InputManager()
        {
            ButtonsAssignments = new Dictionary<Enum, Buttons>();
            KeysAssignments = new Dictionary<Enum, Keys>();

            CurrentKeyboardStates = new KeyboardState[MaxInputs];
            CurrentGamePadStates = new GamePadState[MaxInputs];

            LastKeyboardStates = new KeyboardState[MaxInputs];
            LastGamePadStates = new GamePadState[MaxInputs];

            MouseState = Mouse.GetState();

            TouchPanel.EnabledGestures = GestureType.Tap;
#if WINDOWS_PHONE
            Gestures = new List<GestureSample>();
#endif
        }


        #region CustomKeyAssignment

        public void SubmitCommand(Enum en, Buttons button, Keys key)
        {
            ButtonsAssignments.Add(en, button);
            KeysAssignments.Add(en, key);
        }
        public void ChangeCommand(Enum en, Buttons button, Keys key)
        {
            ButtonsAssignments[en] = button;
            KeysAssignments[en] = key;
        }

        public bool IsButtonAssignmentDown(Enum en, PlayerIndex Index)
        {
            return IsButtonDown(ButtonsAssignments[en], Index);
        }
        public bool IsButtonAssignmentPress(Enum en, PlayerIndex Index)
        {
            return IsButtonPress(ButtonsAssignments[en], Index);
        }
        public bool IsKeyboardAssignmentPress(Enum en)
        {
            return IsKeyboardPress(KeysAssignments[en]);
        }
        public bool IsKeyboardAssignmentDown(Enum en)
        {
            return IsKeyboardDown(KeysAssignments[en]);
        }

        public bool IsAnyAssignementDown(Enum en, PlayerIndex index)
        {
            if (IsButtonAssignmentDown(en, index))
                return true;
            else
                return IsKeyboardAssignmentDown(en);
        }
        public bool IsAnyAssignementPress(Enum en, PlayerIndex index)
        {
            if (IsButtonAssignmentPress(en, index))
                return true;
            else
                return IsKeyboardAssignmentPress(en);
        }


        #endregion

        public PlayerIndex lastPressedPlayer;
               
        public void Update()
        {
            LastGamePadState = GamePadState;
            GamePadState = GamePad.GetState(PlayingPlayer);

            LastMouseState = MouseState;
            MouseState = Mouse.GetState();

            for (int i = 0; i < MaxInputs; i++)
            {
                LastKeyboardStates[i] = CurrentKeyboardStates[i];
                LastGamePadStates[i] = CurrentGamePadStates[i];

                CurrentKeyboardStates[i] = Keyboard.GetState((PlayerIndex)i);
                CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
            }

#if WINDOWS_PHONE
            Touches = TouchPanel.GetState();

            Gestures.Clear();
            while (TouchPanel.IsGestureAvailable)
            {
                GestureSample sample = TouchPanel.ReadGesture();
                Gestures.Add(sample);
            }
#endif
        }
        public void ZeroStates()
        {
            LastGamePadState = new GamePadState();
            GamePadState = new GamePadState();
            MouseState = new MouseState();

            LastMouseState = new MouseState();
            MouseState = new MouseState();

            for (int i = 0; i < CurrentKeyboardStates.Length; i++)
            {
                LastKeyboardStates[i] = new KeyboardState();
                LastGamePadStates[i] = new GamePadState();

                CurrentKeyboardStates[i] = new KeyboardState();
                CurrentGamePadStates[i] = new GamePadState();
            }
        }

        #region Buttons

        public int IsNonActivePlayerAnyButtonDown()
        {
            for (int i = 0; i < CurrentGamePadStates.Length; i++)
            {
                if (i != (int)Engine.Input.PlayingPlayer)
                {
                    GamePadState state = CurrentGamePadStates[i];

                    GamePadButtons b = state.Buttons;
                    ButtonState p = ButtonState.Pressed;
                    if (b.A == p || b.B == p || b.Back == p ||
                        b.X == p || b.Y == p)
                    {
                        return i;
                    }
                }
            }
            return -1;
        }
        public bool IsActivePlayerButtonPress(Buttons Button)
        {
            if (LastGamePadState.IsButtonUp(Button) && GamePadState.IsButtonDown(Button))
            {                
                return true;
            }
            return false;
        }
        public bool IsActivePlayerButtonDown(Buttons Button)
        {
            return GamePadState.IsButtonDown(Button);
        }
        public bool IsActivePlayerButtonUp(Buttons Button)
        {
            return GamePadState.IsButtonUp(Button);
        }
        public bool IsPlayerButtonPress(Buttons Button, PlayerIndex? Index)
        {
            if (Index.HasValue)
            {
                PlayerIndex playerIndex = Index.Value;
                lastPressedPlayer = playerIndex;

                int i = (int)playerIndex;

                return (CurrentGamePadStates[i].IsButtonDown(Button) &&
                    LastGamePadStates[i].IsButtonUp(Button));
            }
            return false;
        }
        public bool IsAnyPlayerButtonPress(Buttons Button)
        {
            return (IsPlayerButtonPress(Button, PlayerIndex.One) ||
                     IsPlayerButtonPress(Button, PlayerIndex.Two) ||
                     IsPlayerButtonPress(Button, PlayerIndex.Three) ||
                     IsPlayerButtonPress(Button, PlayerIndex.Four));
        }
        public bool IsButtonDown(Buttons Button, PlayerIndex? Index)
        {
            if (Index.HasValue)
            {
                PlayerIndex playerIndex = Index.Value;
                lastPressedPlayer = playerIndex;

                int i = (int)playerIndex;

                return (CurrentGamePadStates[i].IsButtonDown(Button));

            }
            return false;
        }

        public bool IsButtonPress(Buttons Button, PlayerIndex? Index)
        {
            if (Index.HasValue)
            {
                PlayerIndex playerIndex = Index.Value;
                lastPressedPlayer = playerIndex;

                int i = (int)playerIndex;

                return (CurrentGamePadStates[i].IsButtonDown(Button) &&
                            LastGamePadStates[i].IsButtonUp(Button));

            }
            return false;
        }
        public bool IsButtonUp(Buttons Button, PlayerIndex? Index)
        {
            if (Index.HasValue)
            {
                PlayerIndex playerIndex = Index.Value;
                lastPressedPlayer = playerIndex;

                int i = (int)playerIndex;

                return (CurrentGamePadStates[i].IsButtonUp(Button));
            }
            return false;
        }
        public bool IsAnyPlayerButtonDown(Buttons Button)
        {
            return (IsButtonDown(Button, PlayerIndex.One) ||
                     IsButtonDown(Button, PlayerIndex.Two) ||
                     IsButtonDown(Button, PlayerIndex.Three) ||
                     IsButtonDown(Button, PlayerIndex.Four));
        }

        #endregion

        #region Keys 
        
        public bool IsKeyboardPress(Keys Keys)
        {
#if WINDOWS
            return CurrentKeyboardStates[0].IsKeyDown(Keys) &&
                   LastKeyboardStates[0].IsKeyUp(Keys);
#else
            return false;
#endif
        }

        public bool IsKeyboardDown(Keys Keys)
        {
#if WINDOWS
            return CurrentKeyboardStates[0].IsKeyDown(Keys);
#else
            return false;
#endif
        }

        public bool IsKeyboardUp(Keys keys)
        {
#if WINDOWS
            return CurrentKeyboardStates[0].IsKeyUp(keys);
#else
            return true;
#endif
        }

        public bool IsChatpadKeyPress(Keys Keys, PlayerIndex? Index)
        {
#if WINDOWS
            return false;
#else
            if (Index.HasValue)
            {
                return CurrentKeyboardStates[(int)Index.Value].IsKeyDown(Keys) &&
                    LastKeyboardStates[(int)Index.Value].IsKeyUp(Keys);
            }
            return false;
#endif
        }
        public bool IsChatpadKeyDown(Keys Keys, PlayerIndex? Index)
        {
#if WINDOWS
            return false;
#else
            if (Index.HasValue)
            {
                return CurrentKeyboardStates[(int)Index.Value].IsKeyDown(Keys);
            }
            return false;
#endif
        }
        public bool IsChatpadKeyUp(Keys Keys, PlayerIndex? Index)
        {
#if WINDOWS
            return false;
#else
            if (Index.HasValue)
            {
                return CurrentKeyboardStates[(int)Index.Value].IsKeyUp(Keys);
            }
            return false;
#endif
        }

        #endregion

        #region Mouse

        public Vector2 MousePos()
        {
            return new Vector2(MouseState.X, MouseState.Y);
        }
        public Rectangle MouseRect()
        {
            return new Rectangle(MouseState.X, MouseState.Y, 1, 1);
        }
        public Rectangle MouseRect(int width)
        {
            return new Rectangle(MouseState.X, MouseState.Y, width, width);
        }
        public Rectangle MouseRect(int width, Camera2D Camera)
        {
            if (Camera != null)
            {
                return new Rectangle(MouseState.X - (int)Camera.Position.X, 
                    MouseState.Y - (int)Camera.Position.Y, width, width);
            }
            else
                return MouseRect(1);
        }
        public bool MouseLeftDown()
        {
            return (MouseState.LeftButton == ButtonState.Pressed);
        }
        public bool MouseLeftUp()
        {
            return (MouseState.LeftButton == ButtonState.Released);
        }
        public bool MouseLeftClick()
        {
            return (MouseLeftDown() &&
                LastMouseState.LeftButton == ButtonState.Released);
        }
        public bool MouseRightClick()
        {
            return (MouseState.RightButton == ButtonState.Pressed);
        }
        public bool MouseRightUp()
        {
            return (MouseState.RightButton == ButtonState.Released);
        }

        #endregion
    }
}
